#include <stdio.h>
#include <stdlib.h>

#include "rectangle.h"
#include "bmpheader.h"

static void _rec_covert_rgb_to_yuv (struct rectangle *rec)
{
	unsigned char yuv[4];
	int row =0, col=0;
	unsigned char * buf = rec->buffer;

	for (row =0;row<rec->y_res;row++) {
		for (col =0;col<rec->x_res;col++) {
#if 1
			yuv[0] =  0.299*(*buf) + 0.587*(*(buf+1)) + 0.114 *(*(buf+2)); //Y
			yuv[1] = -0.147*(*buf) - 0.289*(*(buf+1)) + 0.436 *(*(buf+2)); //U
			yuv[2] =  0.615*(*buf) - 0.515*(*(buf+1)) - 0.100 *(*(buf+2)); //V
#else
			yuv[0] =  0.257*(*buf) + 0.504*(*(buf+1)) + 0.098*(*(buf+2)) + 16;  //Y
			yuv[1] = -0.148*(*buf) - 0.291*(*(buf+1)) + 0.439*(*(buf+2)) + 128; //U
			yuv[2] =  0.439*(*buf) - 0.368*(*(buf+1)) - 0.071*(*(buf+2)) + 128; //V
#endif
			*buf 	 = yuv[1];
			*(buf+1) = yuv[0];
			*(buf+2) = yuv[2];
			buf += 4;
		}
	}
}

static int _rec_draw_into_pixel_arry_image_file (struct rectangle *rec)
{
	int ret =-1;
	FILE *fp = NULL;
	int row =0, col=0;
	unsigned char * buf = rec->buffer;

	fp = fopen (rec->file, "w+");

	if (fp != NULL) {
		for (row =0;row<rec->y_res;row++) {
			for (col =0;col<rec->x_res;col++) {
	       			fwrite(buf, 1, 1,fp);
	       			fwrite(buf+1, 1, 1,fp);
	       			fwrite(buf+2, 1, 1,fp);
				buf +=4;
			}
		}
		fclose (fp);
		ret = 0;
	} else {
		perror ("fopen:");
	}
	return ret;	
}

static int _rec_draw_into_bmp_image_file (struct rectangle *rec, struct bmp_header *bmp)
{
        int ret =-1;
        FILE *fp = NULL;
        int row =0, col=0;
        unsigned char * buf = rec->buffer;

        fp = fopen (rec->file, "w+");

        if (fp != NULL) {
		// Write BMP header here first to file then pixel array
		fwrite(&bmp->signiture, 1, 2,fp);
		fwrite(&bmp->size, 1, 4,fp);
                fwrite(&bmp->reserved1, 1, 2,fp);
                fwrite(&bmp->reserved2, 1, 2,fp);
                fwrite(&bmp->pixel_arry, 1, 4, fp);
                fwrite(&bmp->bmpheader_size, 1, 4,fp);
                fwrite(&bmp->width, 1, 4, fp);
                fwrite(&bmp->height,1,4,fp);
                fwrite(&bmp->planes,1,2,fp);
                fwrite(&bmp->bpps,1,2,fp);
                fwrite(&bmp->compression,1,4,fp);
                fwrite(&bmp->fsize, 1,4,fp);
                fwrite(&bmp->h_res, 1,4,fp);
                fwrite(&bmp->w_res, 1,4,fp);
                fwrite(&bmp->ncolor, 1,4,fp);
                fwrite(&bmp->nimpcolor,1,4,fp);

                for (row =0;row<rec->y_res;row++) {
                        for (col =0;col<rec->x_res;col++) {
                                fwrite(buf, 1, 1,fp);
                                fwrite(buf+1, 1, 1,fp);
                                fwrite(buf+2, 1, 1,fp);
                                buf +=4;
                        }
                }
                fclose (fp);
                ret = 0;
        } else {
                perror ("fopen:");
        }
        return ret;
}

static unsigned char * _rec_allocate_pixel_arry(struct rectangle *rec)
{
	if (rec != NULL)
		return (unsigned char *) malloc (rec->x_res*rec->y_res*4);
	else
		return NULL;
}

static int _rec_fill_background_plane(struct rectangle *rec)
{
	int ret = -1;
        int row =0, col=0;
	unsigned char *buf = rec->buffer;

	if (rec == NULL)
		return ret;

	if (rec->buffer == NULL)
		return ret;
	

	printf ("RGB[%x]: %x %x %x \r\n",rec->line_color,
		(unsigned char)(0x000000FF & rec->line_color >> 16),
		(unsigned char)(0x000000FF & rec->line_color >> 8),
		(unsigned char)(0x000000FF & rec->line_color));

	printf ("RGB[%x]: %x %x %x \r\n",rec->bg_color,
		(unsigned char)(0x000000FF & rec->bg_color >> 16),
		(unsigned char)(0x000000FF & rec->bg_color >> 8),
		(unsigned char)(0x000000FF & rec->bg_color));
        for (row = 0; row <rec->y_res;row++) {
                for (col =0;col<rec->x_res;col++) {
                        if ((row == rec->x1 && col >= rec->y1 && col<=rec->y2 ||
                            (row >= rec->x1 && row<=rec->x1+rec->line_thickness && 
					col >= rec->y1 && col <=rec->y2))||
                            (row == rec->x2 && col >= rec->y1 && col<=rec->y2 ||
                            (row >= rec->x2 && row<=rec->x2+rec->line_thickness && 
					col >= rec->y1 && col<=rec->y2+rec->line_thickness))  ||
                            (col >= rec->y1 && col <=rec->y1+rec->line_thickness && 
					row >= rec->x1 && row <= rec->x2) ||
                            (col >= rec->y2 && col <=rec->y2+rec->line_thickness && 
					row >= rec->x1 && row <= rec->x2+rec->line_thickness))
                        {

				*buf     = (unsigned char)(0x000000FF & rec->line_color >> 16);
				*(buf+1) = (unsigned char)(0x000000FF & rec->line_color >> 8);
				*(buf+2) = (unsigned char)(0x000000FF & rec->line_color);
			} else {
				*buf     = (unsigned char)(0x000000FF & rec->bg_color >> 16);
				*(buf+1) = (unsigned char)(0x000000FF & rec->bg_color >> 8);
				*(buf+2) = (unsigned char)(0x000000FF & rec->bg_color);
			}
			*(buf+3) = 0x00;
			buf += 4;
		}
	}
	return 0;
}

int draw_rectangle_to_console(struct rectangle *rec)
{
	int ret = -1;
        int row =0, col=0;
        int tst =0;
        char buf[20];

        for (row = 0; row <rec->y_res;row++) {
                for (col =0;col<rec->x_res;col++) {
                        if ((row == rec->x1 && col >= rec->y1 && col<=rec->y2 ||
                            (row >= rec->x1 && row<=rec->x1+rec->line_thickness && 
					col >= rec->y1 && col <=rec->y2))||
                            (row == rec->x2 && col >= rec->y1 && col<=rec->y2 ||
                            (row >= rec->x2 && row<=rec->x2+rec->line_thickness && 
					col >= rec->y1 && col<=rec->y2+rec->line_thickness))  ||
                            (col >= rec->y1 && col <=rec->y1+rec->line_thickness && 
					row >= rec->x1 && row <= rec->x2) ||
                            (col >= rec->y2 && col <=rec->y2+rec->line_thickness && 
					row >= rec->x1 && row <= rec->x2+rec->line_thickness))
                        {
				 sprintf (buf, "#");
                        }
			else
				sprintf (buf, ".");
			
			if (tst == 5) {
				tst = 0;
				printf ("%s",buf);
			} else
				tst++;
                }
		printf ("\r\n");
        }
	return ret;
}

int draw_rectangle_raw_yuv_image_file(struct rectangle *rec)
{
	int ret = -1;
	unsigned char *pixel_arry = _rec_allocate_pixel_arry(rec);
	
	if (pixel_arry != NULL) {
		rec->buffer = pixel_arry;

		/* Fill the Background color of plane and draw rectangle with line color */
		ret = _rec_fill_background_plane(rec);

		/* Convert the RGB pixel array to yuv based on provided format of yuv */
		_rec_covert_rgb_to_yuv(rec);

		/* Write the rectangle to file */
		ret = _rec_draw_into_pixel_arry_image_file(rec);

		free (pixel_arry);
		rec->buffer = NULL;

		if (ret != 0)
			printf ("%s: Failed to write image\r\n",__func__);
		else
			printf ("%s: Success\r\n",__func__);
	} else 
		printf ("%s: Failed no memory\r\n",__func__);
	return ret;
}

int draw_rectangle_raw_rgb_image_file(struct rectangle *rec)
{
	int ret = -1;
	unsigned char *pixel_arry = _rec_allocate_pixel_arry(rec);
	
	if (pixel_arry != NULL) {
		rec->buffer = pixel_arry;

		/* Fill the Background color of plane and draw rectangle with line color */
		ret = _rec_fill_background_plane(rec);

		/* Write the rectangle to file */
		ret = _rec_draw_into_pixel_arry_image_file(rec);

		free (pixel_arry);
		rec->buffer = NULL;

		if (ret != 0)
			printf ("%s: Failed to write RGB image\r\n",__func__);
		else
			printf ("%s: Success\r\n",__func__);
	} else 
		printf ("%s: Failed no memory\r\n",__func__);
	return ret;
}

int draw_rectangle_bmp_image_file(struct rectangle *rec)
{
	int ret = -1;
	struct bmp_header bmp;
	unsigned char *pixel_arry = _rec_allocate_pixel_arry(rec);
	
	if (pixel_arry != NULL) {
		rec->buffer = pixel_arry;

		/* Fill the Background color of plane and draw rectangle with line color */
		ret = _rec_fill_background_plane(rec);

	        bmp.signiture 		= 0x4d42;
	        bmp.size 		= sizeof (struct bmp_header) + (rec->x_res*rec->y_res*3);
        	bmp.reserved1 		= 0; 
        	bmp.reserved2 		= 0;
        	bmp.pixel_arry 		= sizeof (struct bmp_header);
        	bmp.bmpheader_size 	= 40;
        	bmp.width 		= rec->x_res;
        	bmp.height 		= rec->y_res;
        	bmp.planes 		= 1;
        	bmp.bpps        	= 24;
        	bmp.compression 	= 0;
        	bmp.fsize       	= (rec->x_res*rec->y_res*3);
        	bmp.h_res       	= 0x0b13;  //rec->x_res;
        	bmp.w_res       	= 0x0b13; //rec->y_res;
		bmp.ncolor      	= 0;
		bmp.nimpcolor   	= 0;

		/* Write the rectangle to file */
		ret = _rec_draw_into_bmp_image_file(rec, &bmp);

		free (pixel_arry);
		rec->buffer = NULL;

		if (ret != 0)
			printf ("%s: Failed to write \r\n",__func__);
		else
			printf ("%s: Success\r\n",__func__);
	} else 
		printf ("%s: Failed no memory\r\n",__func__);
	return ret;
}

int draw_rectangle_jpg_image_file(struct rectangle *rec)
{
	int ret = -1;
	return ret;
}

int draw_rectangle_rgb_buffer(struct rectangle *rec)
{
	int ret = -1;
	unsigned char *pixel_arry = _rec_allocate_pixel_arry(rec);
	
	if (pixel_arry != NULL) {
		rec->buffer = pixel_arry;

		/* Fill the Background color of plane and draw rectangle with line color */
		ret = _rec_fill_background_plane(rec);

		if (ret != 0)
			printf ("%s: Failed to write \r\n",__func__);
		else
			printf ("%s: Success\r\n",__func__);
	} else 
		printf ("%s: Failed no memory\r\n",__func__);
	return ret;
}
